[Batch] 使用 ffmpeg + windows 批次檔 把資料夾底下的影片壓縮

[Batch] 使用 ffmpeg + windows 批次檔 把資料夾底下的影片壓縮

[Batch] Decompress videos under the folder using ffmpeg + batch


2022/07/24 08:23:27

假日來做點不一樣的事情,來把一些影片檔壓縮起來儲存。
這樣簡單的事想說不需要割雞用牛刀寫支程式,寫點 bash 之類的命令就能完成。剛好電腦是 windows 的,windows 的批次檔 batch 又跟平常 unix bash 不太一樣,就來練習寫寫看。

Code

直接先上弱弱的成果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
:: INIT: avoid printing commands below and set codepage to utf-8
@echo off
chcp 65001
echo ===壓縮影片 start===

:: Iterate all mp4s
mkdir .output
for %%I in (*.mp4 *.avi) do (
START /B /WAIT ^
ffmpeg -hwaccel cuda -i "%%~fI" -b:v 4000k -vcodec libx264 -crf 28 -preset medium ".output/%%~nI (CRF=28)%%~xI"
)

:: DONE!
echo ===完成!===
pause

寫好之後包成 .bat 檔,放在要壓縮影片資料夾,點兩下就可以跑了。

解釋

因為很少寫 batch file,這裡做點筆記,以後回來才知道自己在寫什麼

  • Line 1: batch 的註解是用兩個冒號 :: 表示,但要注意這樣註解必須單獨成行
  • Line 2: batch 預設運行的命令都會整個印出來,使用echo off 之後就不會印出執行的命令,只會印出執行的輸出
  • Line 3: 設定字符頁為 UTF-8 (65001),底下 echo 中文才不會是亂碼
  • Line 8: 取得所有資料夾底下 mp4 或 avi 檔的路徑並賦予 loop 變數 %%I。這裡如果要搜尋子資料夾的話可以在 for 後面加上 /r
  • Line 9: 原本直接把 ffmpeg 命令打在這裡,但是發現 cmd 沒等到 ffmpeg 跑完就繼續跑下一步了,所以我們要用 START 開一個新的 cmd,利用 /B 不跳新的框框、/WAIT 等待他跑完
  • Line 10: 重頭戲,我們的 ffmpeg 命令
    • -hwaccel cuda 表示我們使用 cuda GPU 做硬體加速,不過實測也沒快多少就是了
    • -i "%%~fI" 輸入檔案路徑。理論上直接放 "%%I" 也可以。
    • -b:v 4000k 把影片位元速率上限設 4000k,也就是 400 kbps。相同的,-b:a 是代表聲音位元率,在這裡沒有設定。
    • -vcodec libx264 解編碼器使用 H.264。也可以設定成 libx265 使用 H.265,壓縮效果強很多,但是很多播放器不支援 (像是 win 10/11 的預設播放器就顯示不出畫面)
    • -crf 28 設定 CRF 28。CRF 越低品質越好、檔案也越大。 (品質 0 最好 ~ 23 x264預設 ~ 28 x265預設 ~ 51 最差)
    • -preset medium 設定其他設置的樣板,可以設 ultrafast fast slow 等等,跟壓縮檔案一樣,時間設越久壓縮效果越好。見 https://trac.ffmpeg.org/wiki/Encode/H.264
    • 最後放檔名。之前我都很習慣幫輸出加上 -o,結果一直報錯。記得不要加。至於檔名為什麼長這樣請看底下解釋
  • Line 15: 放個 press any key to continue 卡著,不然程式就直接結束無法 debug。

%變數、%%變數

在上面路徑跟檔名的部分,我們看到了奇怪的 %%I 或是更奇怪的 %%~fI,這又是為什麼?

因為 cmd 的一般變數跟迴圈的變數是有分別的。一般變數在取用時會使用 %XXX%,例如

set test=haha123
echo %test%

會輸出 haha123

但如果今天遇到迴圈 for ,因為 cmd 在跑 for 遇到 do (…) 時,會把 (…) 裡面的多行利用 & 串起來,造成取值錯誤的問題。所以循環變數會稱為 %%x。相關解釋可以參閱 這一篇

至於取路徑,這篇 寫的非常完整:

%~I         - expands %I removing any surrounding quotes (")
%~fI - expands %I to a fully qualified path name
%~dI - expands %I to a drive letter only
%~pI - expands %I to a path only
%~nI - expands %I to a file name only
%~xI - expands %I to a file extension only
%~sI - expanded path contains short names only
%~aI - expands %I to file attributes of file
%~tI - expands %I to date/time of file
%~zI - expands %I to size of file
%~$PATH:I - searches the directories listed in the PATH
environment variable and expands %I to the
fully qualified name of the first one found.
If the environment variable name is not
defined or the file is not found by the
search, then this modifier expands to the
empty string

The modifiers can be combined to get compound results:
%~dpI - expands %I to a drive letter and path only
%~nxI - expands %I to a file name and extension only
%~fsI - expands %I to a full path name with short names only

大概紀錄到這裡,下次如果還有寫到 windows 批次檔就可以回來參考。